package cn.virens.common.util.core.stream;

import cn.virens.common.util.exception.APIException;
import cn.virens.common.util.exception.ExceptionUtil;
import org.dromara.hutool.core.thread.ThreadUtil;

import java.util.Arrays;
import java.util.Spliterator;
import java.util.function.Function;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * 流工具
 *
 * @author virens
 */
public class StreamUtil {
    /**
     * 生成空流
     *
     * @param <T> 类型
     * @return 流
     */
    public static <T> Stream<T> empty() {
        return Stream.empty();
    }

    /**
     * 根据数组生成流
     *
     * @param <T>    类型
     * @param values 数组
     * @return 流
     */
    @SafeVarargs
    public static <T> Stream<T> stream(T... values) {
        return stream(values != null ? Arrays.spliterator(values) : null);
    }

    /**
     * 根据迭代器生成流
     *
     * @param <T>      类型
     * @param iterable 迭代器
     * @return 流
     */
    public static <T> Stream<T> stream(Iterable<T> iterable) {
        return stream(iterable != null ? iterable.spliterator() : null);
    }

    /**
     * 根据可分割迭代器生成流(并行流)
     *
     * @param <T>         类型
     * @param spliterator 可分割迭代器
     * @return 流
     */
    public static <T> Stream<T> stream(Spliterator<T> spliterator) {
        return spliterator != null ? StreamSupport.stream(spliterator, false) : empty();
    }

    /**
     * 根据数组生成流(并行流)
     *
     * @param <T>    类型
     * @param values 数组
     * @return 流
     */
    @SafeVarargs
    public static <T> Stream<T> parallelStream(T... values) {
        return parallelStream(values != null ? Arrays.spliterator(values) : null);
    }

    /**
     * 根据迭代器生成流(并行流)
     *
     * @param <T>      类型
     * @param iterable 迭代器
     * @return 流
     */
    public static <T> Stream<T> parallelStream(Iterable<T> iterable) {
        return parallelStream(iterable != null ? iterable.spliterator() : null);
    }

    /**
     * 根据可分割迭代器生成流(并行流)
     *
     * @param <T>         类型
     * @param spliterator 可分割迭代器
     * @return 流
     */
    public static <T> Stream<T> parallelStream(Spliterator<T> spliterator) {
        return spliterator != null ? StreamSupport.stream(spliterator, true) : empty();
    }

    /**
     * 分页查询数据(先并行获取每页数据,再合并)
     *
     * @param total    总数
     * @param pageSize 每页条数
     * @param start    起始页
     */
    public static <T> Stream<T> pageAsync(long total, int pageSize, int start, Function<Integer, T> fun) throws APIException {
        return IntStream.range(start, (int) (total == 0 ? 0 : (total - 1) / pageSize + 1))//
                .mapToObj(page -> ThreadUtil.execAsync(() -> fun.apply(page)))//
                .map(future -> ExceptionUtil.safe1(future::get));
    }

    /**
     * 分页查询数据(先并行获取每页数据,再合并)
     *
     * @param total    总数
     * @param pageSize 每页条数
     * @param start    起始页
     */
    public static <T> Stream<T> pageAsync(int total, int pageSize, int start, Function<Integer, T> fun) throws APIException {
        return pageAsync((long) total, pageSize, start, fun);
    }

    /**
     * 生成分页流
     *
     * @param t        总数
     * @param pageSize 每页条数
     * @param start    起始页
     */
    public static IntStream page(long t, int pageSize, int start) throws APIException {
        return IntStream.range(start, (int) (t == 0 ? 0 : (t - 1) / pageSize + 1));
    }

    /**
     * 生成分页流
     *
     * @param t        总数
     * @param pageSize 每页条数
     * @param start    起始页
     */
    public static IntStream page(int t, int pageSize, int start) throws APIException {
        return page((long) t, pageSize, start);
    }

    /**
     * 生成分页流
     *
     * @param t        总数
     * @param pageSize 每页条数
     */
    public static IntStream page(int t, int pageSize) throws APIException {
        return page(0, t, pageSize);
    }
}
